#ifndef CUDPSERVERTHREAD_HPP
#define CUDPSERVERTHREAD_HPP

#include "SimpleThread.h"
#include "UdpClient.hpp"
#include "common.h"
using namespace cv;

#define SERVER_PORT 2022
#define READ_BUFF_LEN 1024
#define FLAG_BUFF_LEN 1
#define CMD_BUFF_LEN 36

#define R_IMAGE_LINE 640
#define R_IMAGE_ROW 480
#define CHANNEL_NUM 1
#define IMAGE_SIZE R_IMAGE_LINE *R_IMAGE_ROW *CHANNEL_NUM

class CUdpServerThread : public SimpleThread {
 public:
  CUdpServerThread();
  virtual int Run();
  queue<Mat> mMatQue;
  Sem mSemUdpRcvImg;
  Sem mSemUdpRcvCmd;
  int mMode = 0;
  vector<Point2f> mInfraredPoints;

 private:
  void handle_udp_img_msg(int fd);
  void handle_udp_cmd_msg(int fd);
};
CUdpServerThread::CUdpServerThread() { mInfraredPoints.reserve(8); }

int CUdpServerThread::Run() {
  prctl(PR_SET_NAME, (unsigned long)"CUdpServerThread");
  int server_fd, ret;
  struct sockaddr_in ser_addr;
  server_fd = socket(AF_INET, SOCK_DGRAM, 0);  // AF_INET:IPV4;SOCK_DGRAM:UDP
  if (server_fd < 0) {
    printf("create socket fail!\n");
    return -1;
  }

  memset(&ser_addr, 0, sizeof(ser_addr));
  ser_addr.sin_family = AF_INET;
  ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // IP地址，需要进行网络序转换，INADDR_ANY：本地地址
  ser_addr.sin_port = htons(SERVER_PORT);        // 端口号，需要网络序转换

  ret = bind(server_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
  if (ret < 0) {
    printf("socket bind fail!\n");
    return -1;
  }

  //   handle_udp_img_msg(server_fd);  //处理接收到的图像数据
  handle_udp_cmd_msg(server_fd);  // 处理接收到的指令数据

  close(server_fd);
  return 0;
}

void CUdpServerThread::handle_udp_cmd_msg(int fd) {
  int count;
  char *buff;                     // 缓冲区指针
  struct sockaddr_in clent_addr;  // clent_addr用于记录发送方的地址信息
  /* 分配缓冲区内存空间 */
  buff = (char *)malloc(CMD_BUFF_LEN);

  if (NULL == buff)  // 检查分配空间是否成功
  {
    fprintf(stderr, "molloc failed\n");
    return;
  }

  while (1) {
    socklen_t len = sizeof(clent_addr);
    count = recvfrom(fd, buff, CMD_BUFF_LEN, 0, (struct sockaddr *)&clent_addr, &len);
    // recvfrom是拥塞函数，没有数据就一直拥塞
    if (count > 0) {
      for (int i = 0; i < count; ++i) {
        if (buff[i] == 0x55 && (i + CMD_BUFF_LEN - 1) < count) {
          if (buff[i + 1] == 0xaa && buff[i + CMD_BUFF_LEN - 1] == 0xc0) {
            mMode = buff[i + 2];
            cout << "Rcv Mode: " << mMode << endl;
            cout << "Rcv Points:";
            mInfraredPoints.resize(8);
            for (int j = 0; j < 8; ++j) {
              int start = j * 4 + i + 3;
              int x = (int)buff[start + 1] * 256 + (int)buff[start + 0];
              int y = (int)buff[start + 3] * 256 + (int)buff[start + 2];
              mInfraredPoints[j] = Point2f(x, y);
              cout << " [" << mInfraredPoints[j].x << "," << mInfraredPoints[j].y << "]";
            }
            cout << endl;
            // mSemUdpRcvCmd.Post();
          }
        }
      }
    }
    memset(buff, 0, READ_BUFF_LEN);
  }
  free(buff);
}

void CUdpServerThread::handle_udp_img_msg(int fd) {
  char mode;
  socklen_t len;
  int count;
  char *buff;  // 缓冲区指针
  char *bufflag = NULL;
  struct sockaddr_in clent_addr;  // clent_addr用于记录发送方的地址信息
  int rcvsize = 0;
  /* 分配缓冲区内存空间 */
  buff = (char *)malloc(IMAGE_SIZE);
  bufflag = (char *)malloc(READ_BUFF_LEN);
  SUdpDataHead *udp_head = (SUdpDataHead *)malloc(sizeof(SUdpDataHead));

  udp_head->mSendMask = 0;
  udp_head->mRcvMask = 0;
  if (NULL == buff || NULL == bufflag)  // 检查分配空间是否成功
  {
    fprintf(stderr, "molloc failed\n");
    return;
  }

  len = sizeof(clent_addr);

  int flag = 0;

  Mat receiveImg;
  string img_name;

  SUdpData tmp;

  int CUdpServerThread_Count = 0;

  while (1) {
    count = recvfrom(fd, udp_head, sizeof(SUdpDataHead), 0, (struct sockaddr *)&clent_addr, &len);
    if (count != sizeof(SUdpDataHead) || udp_head->mRcvMask != 0 || udp_head->mHeadMark != HEAD_MARK) {
      // printf("count !=
      // sizeof(SUdpDataHead)||udp_head->mHeadMark!=HEAD_MARK\n"); printf("rcv
      // count: %d, local count: %d; RcvMask: %d, HeadMark: %d\n", count,
      // sizeof(SUdpDataHead), udp_head->mRcvMask, udp_head->mHeadMark);
      continue;
    } else {
      printf("frame_idx: %d\n", udp_head->mIndex);
    }

    while (1) {
      flag = 0;
      rcvsize = 0;
      while (1) {
        count = recvfrom(fd, buff + flag * READ_BUFF_LEN, READ_BUFF_LEN, 0, (struct sockaddr *)&clent_addr,
                         &len);  // recvfrom是拥塞函数，没有数据就一直拥塞
        if (count == -1) {
          printf("recieve data fail!\n");
          return;
        } else if (count == 0) {
          continue;
        } else if (count != READ_BUFF_LEN) {
          cout << "count: " << count << endl;
          break;
        }
        memset(bufflag, 0, READ_BUFF_LEN);
        rcvsize += count;
        if (rcvsize >= IMAGE_SIZE) {
          break;
        }
        flag++;
      }

      if (rcvsize != IMAGE_SIZE) {
        cout << "flag = " << flag << endl;
        cout << "fail rcv the pic date  rcvsize = " << rcvsize << endl;
        memset(buff, 0, IMAGE_SIZE);
        goto RCVERROR;
      }
      if (CHANNEL_NUM == 1)
        receiveImg = Mat(R_IMAGE_ROW, R_IMAGE_LINE, CV_8UC1, buff);
      else
        receiveImg = Mat(R_IMAGE_ROW, R_IMAGE_LINE, CV_8UC3, buff);
      tmp.src = receiveImg.clone();
      udp_head->mRcvMask |= SEND_SRC;
      memset(buff, 0, IMAGE_SIZE);

      if (udp_head->mSendMask == udp_head->mRcvMask) {
        // mGPara->pushQue(*udp_head, tmp);
        mMatQue.push(tmp.src);
        CUdpServerThread_Count++;
        // mGPara->m_semUdp.Post();
        mSemUdpRcvImg.Post();
        break;
      }
    }
  RCVERROR:
    if (udp_head->mSendMask != udp_head->mRcvMask) {
      cout << "udp_head->mSendMask != udp_head->mRcvMask" << endl;
      continue;
    }
  }
  free(buff);
  free(bufflag);
}

#endif  // CUDPSERVERTHREAD_H
